using System;
using System.IO;
using System.Collections.Generic;
using System.Text;

using Weazel.Gezel.Model;
using Weazel.Badger;

namespace Weazel.Toad.Application.Items
{
  public class GezelVhdlConversion
  {
    [Serializable]
    public class GezelVhdlConversionSettings
    {
      public enum GezelConversionTarget
      {
        Synthesis,
        Simulation,
        Custom
      }

      private GezelConversionTarget conversionTarget =
        GezelConversionTarget.Synthesis;

      private string destinationFolder;
      private string clockAfterDivisionName;
      private string clockBeforeDivisionName;
      private string resetSignalName;

      private bool divideClock;
      private bool createPortsForUnconnectedNets;
      private bool createClockAndResetProcesses;      
      private bool convertDisplayDirectives;
      
      #region Properties

      public string DestinationFolder
      {
        get { return destinationFolder; }
        set { destinationFolder = value; }
      }

      public bool DivideClock
      {
        get { return divideClock; }
        set { divideClock = value; }
      }

      public GezelConversionTarget ConversionTarget
      {
        get { return conversionTarget; }
        set { conversionTarget = value; }
      }

      public string ClockAfterDivisionName
      {
        get { return clockAfterDivisionName; }
        set { clockAfterDivisionName = value; }
      }

      public string ClockBeforeDivisionName
      {
        get { return clockBeforeDivisionName; }
        set { clockBeforeDivisionName = value; }
      }

      public string ResetSignalName
      {
        get { return resetSignalName; }
        set { resetSignalName = value; }
      }

      public bool CreatePortsForUnconnectedNets
      {
        get { return createPortsForUnconnectedNets; }
        set { createPortsForUnconnectedNets = value; }
      }
      public bool CreateClockAndResetProcesses
      {
        get { return createClockAndResetProcesses; }
        set { createClockAndResetProcesses = value; }
      }
      public bool ConvertDisplayDirectives
      {
        get { return convertDisplayDirectives; }
        set { convertDisplayDirectives = value; }
      }

      #endregion

      public GezelVhdlConversionSettings()
      {
        this.clockAfterDivisionName = "clock";
        this.resetSignalName = "reset";
      }

      /// <summary>
      /// Returns a "badger configuration" object representation
      /// of these settings.
      /// </summary>
      /// <returns></returns>
      public Weazel.Badger.Configuration CreateBadgerConfiguration()
      {
        Weazel.Badger.Configuration configuration =
          new Weazel.Badger.Configuration();

        // set clock signal name (or default)
        configuration.ClockName = 
          clockAfterDivisionName == null ? "clock" : clockAfterDivisionName;

        // set reset signal name (or default)
        configuration.ResetName =
          resetSignalName == null ? "reset" : resetSignalName;

        // set the output folder ..
        configuration.OutputFolder = destinationFolder;

        configuration.ConvertDisplayDirectives = false;

        configuration.CreateClockAndResetGenerationProcesses = false;

        configuration.CreatePortsOnTopEntityForUnconnectedNetsInSystem = true;

        configuration.CreateXilinxIseProjectFile = false;

        configuration.Verbose = false;

        configuration.DivideClock = divideClock;


        return configuration;
      }
    }

    private GezelVhdlConversionSettings settings = new GezelVhdlConversionSettings();
    public GezelVhdlConversionSettings Settings
    {
      get { return settings; }
      set { settings = value; }
    }

    public void ConvertCurrentItem(Model model)
    {
      // report an error if the current item is not a gezel model
      if (!(Application.Instance.SelectedItem is GezelTextFile))
        throw new NotSupportedException("Selected object is not a gezel model");

      // also, check that the settings are available
      if (settings == null)
        throw new NotSupportedException("Settings object is null");
     
      // if the destination folder isnt set, set it to point to the location of the 
      // open gezel model
      if (settings.DestinationFolder == null)
      {        
        // check if the model has been saved
        if (Application.Instance.SelectedItem.Filename == null)
        {
          // abort if the gezel file has not been saved
          string message =
            "Please specify a destination folder or save the gezel file.";

          System.Windows.Forms.MessageBox.Show(message, "Error");
          return;
        }

        // get the directory of the gezel file and use it as the 
        // destination folder
        FileInfo file = 
          new FileInfo(Application.Instance.SelectedItem.Filename);

        settings.DestinationFolder = file.Directory.ToString();
      }

      ConversionContext context = new ConversionContext(
        model, settings.CreateBadgerConfiguration());

      try
      {
        context.Convert();
      }
      catch (Exception e)
      {
        Forms.VhdlConversionFailedForm form =
          new Weazel.Toad.Application.Forms.VhdlConversionFailedForm();

        form.Exception = e;

        form.ShowDialog();
      }

      // conversion successful

      if (Application.Instance.Project != null)
      {
        // get newly created source files
        List<string> files = context.GetVhdlSourceFileNames();

        // add to the project
        foreach(string file in files)
        {
          if (file.EndsWith(".vhd"))
          {
            Items.VhdlTextFile vhdlFile = new VhdlTextFile();
            vhdlFile.Filename = file;
            Application.Instance.Project.AddItem(vhdlFile);
          }
          else
          {
            System.Windows.Forms.MessageBox.Show("Dont know how to add file '" + file + "' to the project.");
          }

         //  Application.Instance.Project.AddItem(
        }
      }
    }
  }
}
